package com.zuo_book.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.dao.DuplicateKeyException;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.Set;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理业务异常
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.error("业务异常: {}", e.getMessage(), e);
        // 直接使用异常的code和message
        Result<Void> result = new Result<>();
        result.setCode(e.getCode());
        result.setMessage(e.getMessage());
        return result;
    }

    /**
     * 处理参数校验异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数校验异常: {}", e.getMessage(), e);
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder message = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            message.append(fieldError.getField())
                   .append(": ")
                   .append(fieldError.getDefaultMessage())
                   .append(", ");
        }
        if (message.length() > 0) {
            message.delete(message.length() - 2, message.length());
        }
        return Result.failure(ResultCode.VALIDATE_FAILED, message.toString());
    }

    /**
     * 处理绑定异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public Result<Void> handleBindException(BindException e) {
        log.error("参数绑定异常: {}", e.getMessage(), e);
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder message = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            message.append(fieldError.getField())
                   .append(": ")
                   .append(fieldError.getDefaultMessage())
                   .append(", ");
        }
        if (message.length() > 0) {
            message.delete(message.length() - 2, message.length());
        }
        return Result.failure(ResultCode.VALIDATE_FAILED, message.toString());
    }

    /**
     * 处理约束违反异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Void> handleConstraintViolationException(ConstraintViolationException e) {
        log.error("约束违反异常: {}", e.getMessage(), e);
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        StringBuilder message = new StringBuilder();
        for (ConstraintViolation<?> violation : violations) {
            String path = violation.getPropertyPath().toString();
            if (path.contains(".")) {
                path = path.substring(path.lastIndexOf(".") + 1);
            }
            message.append(path)
                   .append(": ")
                   .append(violation.getMessage())
                   .append(", ");
        }
        if (message.length() > 0) {
            message.delete(message.length() - 2, message.length());
        }
        return Result.failure(ResultCode.VALIDATE_FAILED, message.toString());
    }

    /**
     * 处理参数类型不匹配异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.error("参数类型不匹配异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.VALIDATE_FAILED, "参数类型不匹配: " + e.getName());
    }

    /**
     * 处理缺少请求参数异常
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("缺少请求参数异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.VALIDATE_FAILED, "缺少请求参数: " + e.getParameterName());
    }

    /**
     * 处理认证相关异常
     */
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler({UsernameNotFoundException.class, BadCredentialsException.class, InternalAuthenticationServiceException.class})
    public Result<Void> handleAuthenticationException(Exception e) {
        log.error("认证异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.UNAUTHORIZED, "用户名或密码错误");
    }

    /**
     * 处理账号禁用异常
     */
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ExceptionHandler(DisabledException.class)
    public Result<Void> handleDisabledException(DisabledException e) {
        log.error("账号禁用异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.ACCOUNT_DISABLED, "账号已被禁用");
    }

    /**
     * 处理权限不足异常
     */
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(AccessDeniedException.class)
    public Result<Void> handleAccessDeniedException(AccessDeniedException e) {
        log.error("权限不足异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.FORBIDDEN, "权限不足");
    }

    /**
     * 处理数据库唯一约束异常
     */
    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.OK)
    public Result<Void> handleDuplicateKeyException(DuplicateKeyException e) {
        String message = e.getMessage();
        log.warn("数据库唯一约束异常: {}", message);
        
        // 点赞冲突，返回友好提示
        if (message.contains("comment_like.uk_comment_user") || 
            message.contains("note_like.uk_note_user")) {
            return Result.success("您已经点过赞了");
        }
        
        // 其他唯一约束冲突
        return Result.failure(ResultCode.VALIDATE_FAILED, "数据已存在");
    }

    /**
     * 处理其它异常
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        log.error("未知异常: {}", e.getMessage(), e);
        return Result.failure(ResultCode.FAILED, "系统繁忙，请稍后再试");
    }
} 